# coding=utf-8

import time

from ChatSession import ChatSession
from ChatRoom import ChatRoom
from UserData import UserData


LINE = True

# 处理各种命令
class CommandHandler:

    def __init__(self, name):
        self.name = name
        # key = socket(socket), value = session(class ChatSession)
        self.sessions = {}
        # key = room_name(str), value = room(class ChatRoom)
        self.rooms = {}
        self.user_data = UserData()
        # key = username(str), value = session(class ChatSession)
        self.logged = {}
        self.is_begin_game = False

    def disconnect(self, sock):
        session = self.sessions[sock]
        # 登出的合法性由logout函数内部保证，这里不做检查
        self._logout(session)
        # 最后pop
        self.sessions.pop(sock)

    # 处理服务器关闭时需要处理的行为，目前是关闭数据库
    def close(self):
        self.user_data.close()

    # 对所有连接的用户广播消息，包括未登录的
    def _broadcast(self, message):
        for session in self.sessions:
            self.sessions[session].send(message)

    # 大厅中聊天
    def _chat_all(self, speaker, message):
        if not message:
            speaker.send("Empty message.")
        else:
            message = "[%s] %s: %s" % (self.name, str(speaker.get_name()), message)
            self._broadcast(message)

    # 查询所有已登录用户
    def _who(self, speaker):
        message = "The following are logged in:"
        speaker.send(message)
        for username in self.logged:
            speaker.send(username)

    # 私聊
    def _chat_to(self, session, line):
        if not line:
            session.send("Missing username.")
        else:
            parts = line.strip().split()
            username = parts[0]
            if not self.user_data.is_existed(username):
                session.send("%s is not existed." % username)
            elif username not in self.logged:
                session.send("%s is off line." % username)
            elif len(parts) == 1:
                session.send("Empty message.")
            else:
                message = parts[1]
                message = session.get_name() + ": " + message
                self.logged[username].send(message)

    # 查询当前所有房间
    def _list(self, session):
        if not self.rooms:
            session.send("There is no room.")
        else:
            session.send("There are following rooms:")
            for room_name in self.rooms:
                session.send("[%s]" % room_name)

    # 进入房间，在创建房间成功及进入房间合法时调用
    def _enter_room(self, session, room_name):
        # 首先离开原房间
        self._leave(session)
        # 进入新的房间
        self.rooms[room_name].add(session)
        session.enter(room_name)

    # 新建房间
    def _create(self, session, room_name):
        if not room_name:
            session.send("Missing room name.")
        elif room_name in self.rooms:
            session.send("Room name %s is token." % room_name)
        else:
            room = ChatRoom(room_name)
            self.rooms[room_name] = room
            self._enter_room(session, room_name)

    # 进入房间
    def _enter(self, session, room_name):
        if not room_name:
            session.send("Missing room name.")
        elif room_name not in self.rooms:
            session.send("Room %s is not existed." % room_name)
        elif session.is_in_room(room_name):
            session.send("You are already in this room.")
        else:
            self._enter_room(session, room_name)

    # 删除房间，在房间中没有任何用户时调用
    def _delete_room(self, room_name):
        self.rooms.pop(room_name)

    # 离开房间
    def _leave(self, session):
        room_name = session.leave()
        if room_name:
            # 若房间中没人，则删除房间
            if self.rooms[room_name].remove(session) == 0:
                self._delete_room(room_name)
            return True
        else:
            return False

    # 参与游戏
    def _game(self, session, expression):
        room_name = session.get_room_name()
        if not room_name:
            session.send("You are not in any room.")
        elif not expression:
            session.send("Missing expression.")
        else:
            self.rooms[room_name].play_game(session, expression)

    # 房间内聊天
    def _chat(self, session, message):
        room_name = session.get_room_name()
        if not room_name:
            session.send("You are not in any room.")
        elif not message:
            session.send("Empty message.")
        else:
            self.rooms[room_name].chat(session, message)

    # 查询当前房间内的用户
    def _look(self, session):
        room_name = session.get_room_name()
        if not room_name:
            session.send("You are not in any room.")
        else:
            self.rooms[room_name].look(session)

    # 登录
    def _login(self, session, line):
        if not line:
            session.send("Missing username.")
        else:
            parts = line.strip().split()
            if len(parts) == 1:
                session.send("Missing password.")
            else:
                username = parts[0]
                password = parts[1]
                if not self.user_data.is_existed(username):
                    session.send("Username %s is not existed." % username)
                elif not self.user_data.verify(username, password):
                    session.send("Wrong password.")
                elif username in self.logged:
                    session.send("You are logged in somewhere else.")
                else:
                    self.logged[username] = session
                    session.login(username)

    # 注册
    def _register(self, session, line):
        if not line:
            session.send("Missing username.")
        else:
            parts = line.strip().split()
            username = parts[0]
            if self.user_data.is_existed(username):
                session.send("Username %s is token." % username)
            elif len(parts) == 1:
                session.send("Missing password.")
            else:
                password = parts[1]
                self.user_data.insert_user(username, password)
                self.logged[username] = session
                session.login(username)

    # 登出
    def _logout(self, session):
        if session.is_login():
            # 首先离开房间，若房间中没人会删除房间
            self._leave(session)
            username = session.get_name()
            # 更新在线时长，在线时长仅在用户登出时更新，服务器关闭时也会调用该函数
            online_time = session.online_time()
            self.user_data.update_online_time(username, online_time)
            self.logged.pop(username)
            session.logout()
            print username, "has logged out."

    # 将在线时长由秒转换为一个合适的显示方式
    def _convert_time(self, tm):
        second = int(tm)
        minute = 0
        if second > 60:
            minute = second / 60
            second %= 60
        str_time = "%d sec" % second
        hour = 0
        if minute > 60:
            hour = minute / 60
            minute %= 60
        if minute or hour:
            str_time = "%d min " % minute + str_time
        day = 0
        if hour > 24:
            day = hour / 24
            hour %= 24
        if hour or day:
            str_time = "%d hour " % hour + str_time
        if day:
            str_time = "%d day " % day + str_time
        return str_time

    # 查询在线时长，查询不会修改数据库中的数据，仅当登出时更新
    def _online(self, session):
        online_time = self.user_data.get_online_time(session.get_name())
        online_time += session.online_time()
        session.send("Total online time is: %s." % self._convert_time(online_time))

    # 处理未知命令
    def _unknown(self, speaker, cmd):
        message = "Unknown command \"%s\"" % cmd
        speaker.send(message)

    # 处理命令
    def _handle_command(self, session, line):
        parts = line.strip().split(' ', 1)
        cmd = parts[0].strip()
        print "%s: %s" % (session.get_name(), line)
        if len(parts) > 1:
            line = parts[1].strip()
        else:
            line = ""
        if session.is_login():
            if cmd == "chatall":
                self._chat_all(session, line)
            elif cmd == "who":
                self._who(session)
            elif cmd == "chatto":
                self._chat_to(session, line)
            elif cmd == "list":
                self._list(session)
            elif cmd == "online":
                self._online(session)
            elif cmd == "create":
                self._create(session, line)
            elif cmd == "enter":
                self._enter(session, line)
            elif cmd == "game":
                self._game(session, line)
            elif cmd == "chat":
                self._chat(session, line)
            elif cmd == "leave":
                self._leave(session)
            elif cmd == "look":
                self._look(session)
            elif cmd == "logout":
                self._logout(session)
            elif cmd == "login" or cmd == "register":
                session.send("You are already logged in, please logout first.")
            else:
                self._unknown(session, cmd)
        else:
            if cmd == "login":
                self._login(session, line)
            elif cmd == "register":
                self._register(session, line)
            else:
                session.send("Please login or register first.")

    # 处理客户端发送来的字符，根据长度判断是否为整行数据
    def handle_data(self, sock, data):
        session = self.sessions[sock]
        if len(data) > 2 and session.is_terminator(data[-2:]):
            self._handle_command(session, data[:-2])
        elif session.is_terminator(data):
            line = session.pop_data()
            self._handle_command(session, line)
        else:
            session.collect_data(data)

    # 结束游戏，通知各个房间
    def _end_game(self):
        for room_name in self.rooms:
            self.rooms[room_name].end_game()

    # 开始游戏，通知各个房间
    def begin_game(self):
        self.is_begin_game = True
        for room_name in self.rooms:
            self.rooms[room_name].begin_game()

    # 处理每个半点发布一次游戏
    def process_game(self):
        tm_min = time.localtime().tm_min
        TM = 5
        if not self.is_begin_game and (tm_min % TM == 0):
            self._end_game()
            self._broadcast(time.asctime(time.localtime()))
            self.begin_game()
        if tm_min % TM:
            self.is_begin_game = False

    # 新建会话
    def add_session(self, sock):
        session = ChatSession(sock)
        self.sessions[sock] = session
